import os, shutil
from xml.etree import ElementTree

import pyglet
import cocos
from cocos.director import director
from cocos.menu import *
from cocos.actions import *
from cocos.tiles import _xml_to_python

from gamelib import level, inventory, shopping, menustyle


MAPDAT = 'mapdata.dat'

THRESHHOLD = 30

def load_data(directory):
    '''Parse the save directory to find level files.

    Pull out the map properties to use in the global map.
    '''
    r = {}
    for filename in os.listdir(directory):
        if not filename.startswith('level-'): continue
        if not filename.endswith('.xml'): continue

        # load the map file
        filename = os.path.join(directory, filename)
        tree = ElementTree.parse(filename)
        d = {}
        for tag in tree.findall('rectmap/property'):
            name = tag.get('name')
            type = tag.get('type') or 'unicode'
            value = tag.get('value')
            d[name] = _xml_to_python[type](value)

        # fix up some bits
        d['world-position'] = map(int, d['world-position'].split(','))
        d['mapfile'] = filename
        r[d['name']] = d
    return r

class WorldMap(cocos.layer.Layer):
    is_event_handler = True

    def show_location(self, loc, new=False):
        x, y = loc['world-position']
        image = pyglet.resource.image(loc['icon'])
        loc['sprite'] = cocos.sprite.Sprite(image, (x, y))
        self.add(loc['sprite'])
        if new:
            loc['sprite'].do(Blink(5, 1))

        loc['label'] = cocos.text.Label(loc['name'], color=(0,0,0,255),
           anchor_x='center', anchor_y='bottom', position=(x, y+image.height//2))
        self.add(loc['label'])

    def on_enter(self):
        super(WorldMap, self).on_enter()

        new_locs = set()
        savedir = self.parent.directory
        for file in self.parent.party.maps_seen:
            path = os.path.join(savedir, file)
            if os.path.exists(path):
                continue
            shutil.copyfile(os.path.join('data', file), path)
            new_locs.add(path)

        pyglet.resource.reindex()

        self.locs = load_data(savedir)

        w, h = director.get_window_size()

        for loc in self.locs.values():
            self.show_location(loc, loc['mapfile'] in new_locs)

        image = pyglet.resource.image('world-overview-map-blank.png')
        self.map = cocos.sprite.Sprite(image, anchor=(0, 0))
        self.add(self.map, z=-1)

        image = pyglet.resource.image('button-quit.png')
        self.quit_button = cocos.sprite.Sprite(image, position=(0, h),
            anchor=(0, image.height))
        self.add(self.quit_button)

        image = pyglet.resource.image('button-manage-party.png')
        self.manage_button = cocos.sprite.Sprite(image, position=(0, h - image.height - 4),
            anchor=(0, image.height))
        self.add(self.manage_button)


    def on_exit(self):
        super(WorldMap, self).on_exit()

        for loc in self.locs.values():
            if 'sprite' not in loc: continue
            self.remove(loc['sprite'])
            self.remove(loc['label'])

        self.locs = None

        self.remove(self.map)

    curloc = None
    def on_mouse_motion(self, x, y, dx, dy):
        locs = self.locs
        found = None
        for loc in locs.values():
            if 'sprite' not in loc: continue
            lx, ly = loc['world-position']
            if ((lx-x)**2 + (ly-y)**2)**.5 > THRESHHOLD:
               continue
            found = loc['name']
            break
        else:
            if self.curloc:
                self.locs[self.curloc]['label'].element.color = (0,0,0,255)
                self.curloc = None
            return False

        if found != self.curloc:
            if self.curloc:
                self.locs[self.curloc]['label'].element.color = (0,0,0,255)
            self.curloc = found
            self.locs[self.curloc]['label'].element.color = (255,0,0,255)

        return True

    def on_mouse_press(self, x, y, buttons, modifiers):
        bx, by = self.quit_button.position
        if (x > bx and x < bx + self.manage_button.width and
                y > by - self.manage_button.height and y < by):
            director.replace(cocos.scene.Scene(QuitSave('Save?', self.parent.party)))
            return True

        bx, by = self.manage_button.position
        if (x > bx and x < bx + self.manage_button.width and
                y > by - self.manage_button.height and y < by):
            self.go_inventory()
            return True

        if not self.curloc: return False

        loc = self.locs[self.curloc]
        if loc['type'] == 'tactical':
            l = level.Level(self.parent.party, loc['mapfile'])
        else:
            # just go shopping
            l = cocos.scene.Scene(shopping.ShoppingLayer(self.parent.party))
        director.push(l)
        return True

    def on_key_press(self, key, modifiers):
        if key == pyglet.window.key.ESCAPE:
            director.replace(cocos.scene.Scene(QuitSave('Save?', self.parent.party)))
            return True
        return False

    def go_inventory(self):
        director.push(inventory.PartyInventoryScreen(self.parent.party))

class MapScene(cocos.scene.Scene):
    def __init__(self, directory, party):
        super(MapScene, self).__init__()
        self.directory = directory
        self.party = party

    def on_enter(self):
        super(MapScene, self).on_enter()
        self.add(WorldMap())


class QuitSave(menustyle.MyStyleMenu):
    def __init__(self, title, party):
        super(QuitSave, self).__init__(title)
        self.party = party

    def on_enter(self):
        super(QuitSave, self).on_enter()

        # ugh, menu should DO this
        for child in self.get_children():
            self.remove(child)

        options = [
            MenuItem("Save and Quit", self.save_game),
            MenuItem('Quit without saving', self.on_quit),
        ]

        self.create_menu(options)

    def on_quit(self):
        self.parent.end()

    def save_game(self):
        savedir = 'save_game'
        self.party.save(savedir)
        self.parent.end()

